/*=============================================================================
*
*   Copyright (C) 2020 All rights reserved.
*
*   Filename:		build_crack.hpp
*
*   Author: Wang Zhecheng - wangzhecheng@yeah.net
*
*   Date: 2020-03-24 14:42
*
*   Last Editors: Wang Zhecheng - wangzhecheng@yeah.net
*
*   Last modified:	2020-03-30 20:10
*
*   Description:
*
=============================================================================*/
#ifndef BUILD_CRACK_H
#define BUILD_CRACK_H

#include "../geometry/mesh/build_mesh.hpp"
#include "../geometry/shape/subdivide.hpp"

namespace geoxfem {

namespace geometry {
struct crack {};

template <>
struct build_mesh_impl<crack> {
  using ptree = boost::property_tree::ptree;

  template <typename Model>
  static void
  apply(const ptree& root, Model& model, typename Model::Crack& crack) {
    using DimensionType = typename Model::DimensionType;
    using CouplePolicy  = typename Model::CouplePolicy;
    using Shape         = typename Model::Shape;
    using point_type    = typename traits::point_type<DimensionType>::type;
    {
      GEOXFEM_LOG_SEV(info) << "Building nodes from source file...";
      /* 1. build nodes, iterator all nodes record from xml source file */
      for(auto& node_data : root.get_child("nodes")) {
        point_type point = model.append(point_type(node_data.second));
        std::unique_ptr<Shape> sp_vertex =
          Shape::getFactory().create("Vertex", {point});
        set_nodal_dofs<CouplePolicy>::apply(sp_vertex->toVertex());
        GEOXFEM_LOG_SEV(trace) << "Building " << *sp_vertex;
        model.append(sp_vertex, &crack);
      }
    }
    {
      GEOXFEM_LOG_SEV(info) << "Building elements from source file...";
      /* 2. build element, iterator all elements record from xml source file */
      for(auto& elem_data : root.get_child("elements")) {
        /* 2.1 assemble shape from input data */
        std::string type = elem_data.second.template get<std::string>("type");
        std::vector<point_type> node_list;
        for(auto& v : elem_data.second.get_child("nodes")) {
          size_t     point_id = std::stoul(v.second.data());
          point_type point    = model.getPoint(point_id).shallowClone();
          node_list.emplace_back(point);
        }
        std::unique_ptr<Shape> sp_crack_segment =
          Shape::getFactory().create(type, node_list);
        size_t id = elem_data.second.template get<size_t>("id");
        sp_crack_segment->setIndex(id);
        GEOXFEM_LOG_SEV(trace) << "Building " << *sp_crack_segment;
        /* 2.2 add new shape into model and given crack */
        auto p_crack_segment = model.append(sp_crack_segment, &crack);
        /* 2.3 accumulate nodal weight */
        p_crack_segment->setNodalWeight();
        /* 2.4 sub divide main mesh */
        algorithm::SubDivide(p_crack_segment->toSegment(), *model.getMesh());
      }
    }
    return;
  }
}; /*}}}*/

}  // namespace geometry
}  // namespace geoxfem
#endif /* BUILD_CRACK_H */
